package com.dhcc.DRGsHosp.facade.impl;

import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Pattern;

import javax.inject.Named;

import org.codehaus.jackson.map.ObjectMapper;
import org.openkoala.koala.commons.InvokeResult;
import org.springframework.beans.factory.annotation.Autowired;

import com.dhcc.DRGsHosp.application.DRGVersionApplication;
import com.dhcc.DRGsHosp.application.DrgServiceGroupApplication;
import com.dhcc.DRGsHosp.core.domain.DRGVersion;
import com.dhcc.DRGsHosp.facade.DrgServiceGroupFacade;
import com.dhcc.DRGsHosp.facade.GroupServiceFacade;
import com.dhcc.DRGsHosp.infra.util.Arith;
import com.dhcc.DRGsHosp.infra.util.DrgsIndex;
import com.dhcc.DRGsHosp.infra.util.GlobalData;
import com.dhcc.DRGsHosp.infra.util.MonitorResultUtil;
import com.dhcc.DRGsHosp.infra.util.NotInGroupReasonUtil;
import com.dhcc.DRGsHosp.infra.util.StringUtils;

/**
 * @title :DrgServiceGroupFacadeImpl.java
 * @description :DRGs分组服务
 * @author :LiQingYang
 * @date :2017年3月17日
 * @version :2.4.0
 * @copyright :DHCC 2013-2017
 */
@Named("drgsHospFacadeImpl14")
public class DrgServiceGroupFacadeImpl implements DrgServiceGroupFacade{

	@Autowired
	private DRGVersionApplication drgVersionApplication;
	@Autowired
	private DrgServiceGroupApplication drgServiceGroupApplication;
	@Autowired 
	private GroupServiceFacade groupServiceFacade;
	
	public int totalMrCountProgress; //初始化获取总病例数
	
	public int totalMrGt60Count;//初始化获取大于60天病例总数
		
	public int mrGt60Count; //进度中获取大于60天病例数
	
	public Integer mrAssembleCount;//进度中获取组装病例数
		
	private String isICDMatch;//是否进行ICD对照
	
	private String drgGroupVer;//分组器字典版本号
	
	private String drgVersionDesc;//分组器版本描述
	
	private String verRegion;//分组器版本地区代码
	
	private String groupAddr;//分组地址
	
	private int[] processCaseCnt = {0,0,0,0,0}; //总病例数进度, 分组病例数进度, >60天病例, 未入组病例数, 报错病例数
	
	private List<String> drgsInGroupMap;//获取当前已经分到的DRGs组
	
	private int  drgsTotalCount;//drgs字典总组数
	
	private int mrProducerTheadCount = 50;//数据组装线程数
	
	private int notInAll; //总的未入组数--未入组原因更新用
	
	private double notInUpdate; //已经更新的未入组数--未入组原因更新用
	
	private boolean groupAgain;//未入组病例是否再分组
	
	/**
	 * 
	 *  @Description：获取数据总量
	 *  @Author：liuhongjun 
	 *  @see com.dhcc.DRGsHosp.facade.DrgServiceGroupFacade#getMrCount(java.lang.String, java.lang.String, java.lang.String)
	 */
	public Object[] getMrCount(String dateFrom, String dateTo, String dateType){
		List<Object[]> mrCountList =  drgServiceGroupApplication.getMrCount(dateFrom, dateTo,dateType);
		if(!mrCountList.isEmpty()){
			Object[] cnObj = mrCountList.get(0);
			totalMrCountProgress = Integer.parseInt(cnObj[0]==null?"0":cnObj[0].toString());//初始化获取总病例数
			totalMrGt60Count = Integer.parseInt(cnObj[1]==null?"0":cnObj[1].toString());//初始化获取大于60天病例总数
			return cnObj;
		}
		return null;
	}
	/**
	 *  @Description：开始分组
	 *  @Author：liuhongjun 
	 *  @see com.dhcc.DRGsHosp.facade.DrgServiceGroupFacade#drgGroupOfMrData(java.lang.String, java.lang.String, java.lang.String)
	 */
	@Override
	public InvokeResult drgGroupOfMrData(String dateFrom, String dateTo, String dateType){	
		//获取是否ICD对照
		isICDMatch = getICDMatchResult();
		processCaseCnt[0] = 0;
		processCaseCnt[1] = 0;
		processCaseCnt[2] = 0;
		processCaseCnt[3] = 0;
		processCaseCnt[4] = 0;
		mrGt60Count = 0; //大于60天病例数
		mrAssembleCount = 0;//组装病例数
		drgsInGroupMap = new ArrayList<String>();
		groupAgain=false;
		drgGroupVer =GlobalData.sysConfig.get("GROUP_VER");
		drgVersionDesc = drgVersionApplication.getDrgDescByVerCode(drgGroupVer);
		verRegion=drgVersionApplication.getDrgRegionByVerCode(drgGroupVer);
		//获取分组地址
		if(drgVersionDesc!=null&&drgVersionDesc.indexOf("北京2016版")>=0){
			groupAddr = GlobalData.sysConfig.get("GROUP_ADDER_2016") ;
		}
		else{
			groupAddr =  GlobalData.sysConfig.get("GROUP_ADDER") ;
		}
		boolean groupURLTest=groupURLTest();//分组器地址测试
		if(!groupURLTest){
			return InvokeResult.failure("分组地址配置错误");
		}
		String icdDiaVerConfig=null;
		String icdOperVerConfig=null;
		DRGVersion drgVersion=getICDVersion(drgGroupVer);
		if(drgGroupVer!=null){
			icdDiaVerConfig=drgVersion.getIcd10Version();
			icdOperVerConfig=drgVersion.getIcd9Version();
		}
		String mrProducerTheadCnt = GlobalData.sysConfig.get("PRODUCER_THREAD_CNT");//获取组装线程数量
		if(StringUtils.hasLength(mrProducerTheadCnt)){
			mrProducerTheadCount = Integer.parseInt(mrProducerTheadCnt);//组装线程数量
		}
		if(drgVersionDesc!=null&&!(drgVersionDesc.indexOf("北京2016版")>=0)){
			mrProducerTheadCount = mrProducerTheadCount<19?mrProducerTheadCount:19;
		}
		groupAgain = "1".equals(GlobalData.sysConfig.get("GROUPINGAGAIN"));//是否再分组
		ExecutorService mrAssembleGroupPools = Executors.newFixedThreadPool(mrProducerTheadCount);//多线程分组线程池
		
		for(int i=0; i<mrProducerTheadCount; i++){
			MrInfo mr = new MrInfo(dateFrom, dateTo,dateType, i, isICDMatch,icdDiaVerConfig,icdOperVerConfig);
			mrAssembleGroupPools.execute(mr);
		}
		
		mrAssembleGroupPools.shutdown();
		while(!mrAssembleGroupPools.isTerminated()){
			
		}
		Map<String, Object> drgGroupInfoMap = new HashMap<>();
		drgGroupInfoMap.put("mrGt60CountCurr", processCaseCnt[2]);//当前获取到的大于60天病例数
		drgGroupInfoMap.put("mrAssembleCountCurr", processCaseCnt[0]);//当前多线程组装病例数
		drgGroupInfoMap.put("mrGroupCount", processCaseCnt[1]);//当前分组病例数
		drgGroupInfoMap.put("notInCaseCnt", processCaseCnt[3]);//未入组病例数
		drgGroupInfoMap.put("drgVersionDesc", drgVersionDesc);//分组器版本
		drgGroupInfoMap.put("drgCountCurr", drgsInGroupMap.size());//获取当前已经分到的DRGs组数
		drgGroupInfoMap.put("groupErrorCaseCnt", processCaseCnt[4]);//分组报错的病例数
		return InvokeResult.success(drgGroupInfoMap);	
	}
	/**
	 * 
	 * @ClassName: MrInfo  
	 * @Description ：    新的分组线程类
	 * @Date: 2018年11月12日 上午9:18:41  
	 * @Author WENYI 
	 * @Version 2.5.0 DHC-DRGs
	 */
	private class MrInfo extends Thread{
		
		String dateFrom;
		String dateTo;
		String isICDMatch;
		String icdDiaVerConfig;
		String icdOperVerConfig;
		String dateType;
		
		MrInfo(String dateFrom, String dateTo, String dateType ,int i, String isICDMatch,String icdDiaVerConfig, String icdOperVerConfig){
			this.dateFrom = MonitorResultUtil.addDay(dateFrom, i);
			this.dateTo = dateTo;
			this.isICDMatch = isICDMatch;
			this.icdDiaVerConfig = icdDiaVerConfig;
			this.icdOperVerConfig = icdOperVerConfig;
			this.dateType=dateType;
		}
		
		@Override
		public void run(){
			String reg = "^(-?\\d+)(\\.\\d+)?$";
			Pattern p = Pattern.compile(reg); //判断是否为浮点数
			while(dateFrom.hashCode()<=dateTo.hashCode()){
				List<Map<String, Object>> mrList = drgServiceGroupApplication.findMrInfo(dateFrom,dateType);
				synchronized (processCaseCnt) {
					processCaseCnt[0]+=mrList.size();
				}
				for(Map<String, Object> m: mrList){
					try{
						if(m.get("ACCTUAL_DAYS")!=null&&p.matcher(m.get("ACCTUAL_DAYS").toString()).find()&&(Double.valueOf(m.get("ACCTUAL_DAYS").toString())).intValue() < 61){
							String diags = m.get("DIAGS")!=null?m.get("DIAGS").toString():null;
							if(StringUtils.hasLength(diags)){
								m.put("DIAGS_CODE", Arrays.asList(diags.split(",")));
							}
							String opers = m.get("OPERS")!=null?m.get("OPERS").toString():null;
							if(StringUtils.hasLength(opers)){
								m.put("OPERS_CODE", Arrays.asList(opers.split(",")));
							}
							Map<String, Object> mrInfoMap=groupServiceFacade.dataGenerate(m, drgVersionDesc, isICDMatch, icdDiaVerConfig, icdOperVerConfig);
							if(drgVersionDesc!=null&&drgVersionDesc.indexOf("北京2016版")>=0){
								bj2016groupService(mrInfoMap);
							} else {
								bjBefore2016GroupService(mrInfoMap);
							}
							synchronized (processCaseCnt) {
								processCaseCnt[1]++;
							}
						}else{
							synchronized (processCaseCnt) {
								processCaseCnt[2]++;
							}
						}
					}catch(Exception e){
						e.printStackTrace();
					}
				}
				dateFrom = MonitorResultUtil.addDay(dateFrom, mrProducerTheadCount);
			}
		}
	}
	/**
	 * 
	 * @methodname    : getDRGsCountByVerCode
	 * @description   : 根据分组器版本编码获取字典表DRGs组数与版本描述
	 * @param         : 
	 * @author        : LiQingYang
	 * @return        :
	 * @date          : 2017年3月24日
	 */
	public Map<String,String> getDRGsCountByVerCode(){
		Map<String,String> result=new HashMap<>();
		//获取配置的分组器版本号
		drgGroupVer =GlobalData.sysConfig.get("GROUP_VER");
		drgVersionDesc = drgVersionApplication.getDrgDescByVerCode(drgGroupVer);
		verRegion=drgVersionApplication.getDrgRegionByVerCode(drgGroupVer);
		drgsTotalCount = drgServiceGroupApplication.getDRGsCountByVerCode(drgGroupVer);
		//获取分组地址
		if(drgVersionDesc!=null&&drgVersionDesc.indexOf("北京2016版")>=0){
			groupAddr = GlobalData.sysConfig.get("GROUP_ADDER_2016") ;
		}
		else{
			groupAddr =  GlobalData.sysConfig.get("GROUP_ADDER") ;
		}
		result.put("drgsTotalCount", drgsTotalCount+"");
		result.put("drgVersionDesc", drgVersionDesc);
		return result;
	}

	/**
	 * 测试分组地址是否可用
	 * @return
	 */
	private boolean groupURLTest(){
		Map<String, Object> mrInfoMap = new HashMap<String, Object>();
		mrInfoMap.put("B_WT4_V1_ID", (int)((Math.random()*9+1)*100000)+"");//随机生成6位数字代替病案号
		mrInfoMap.put("AGE", "11");//年龄
		mrInfoMap.put("GENDER", "男");//性别
		mrInfoMap.put("TOTAL_EXPENSE", "12345");//总费用
		mrInfoMap.put("DISEASE_CODE", "A00.001");//主要诊断编码
		mrInfoMap.put("ACCTUAL_DAYS", "1");//住院天数
		mrInfoMap.put("SF0108", "-1");
		mrInfoMap.put("SF0100", "-1");
		mrInfoMap.put("SF0102", "-1");
		mrInfoMap.put("SF0104", "-1");
		if(!(drgVersionDesc!=null&&drgVersionDesc.indexOf("北京2016版")>=0)){
			mrInfoMap.put("ver", "北京2015版");
		}
		try {
			URL url = new URL("http://" + groupAddr);
			ObjectMapper mapper = new ObjectMapper();
			// 将map转化为JSON格式的字符串
			String json = mapper.writeValueAsString(mrInfoMap);
			HttpURLConnection con = (HttpURLConnection) url.openConnection();
			con.setDoOutput(true);
			con.setDoInput(true);
			con.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
			con.setRequestProperty("Accept", "application/json");
			con.setRequestMethod("POST");
			OutputStream os = con.getOutputStream();
			os.write(json.getBytes("UTF-8"));
			os.flush();
			int HttpResult = con.getResponseCode();
			if (HttpResult == HttpURLConnection.HTTP_OK) {
				return true;
			} 
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}
	/**
	 * 
	 * @methodname    : getICDMatch
	 * @description   : 获取是否进行ICD对照
	 * @param         : 
	 * @author        : LiQingYang
	 * @return        : String
	 * @date          : 2017年3月17日
	 */
	private String getICDMatchResult() {
		String isICDMatch = "0";
		String matchResult = GlobalData.sysConfig.get("ICD_MATCH");
		if(StringUtils.hasLength(matchResult)){
			if("true".equals(matchResult)){
				isICDMatch = "1";
			}
		}	
		return isICDMatch;
	}
	/**
	 * 北京版分组器分组--2014/2015版
	 * @param mrInfoMap
	 */
	private void bjBefore2016GroupService(Map<String, Object> mrInfoMap){
		//分组器调用					
		Map<String,Object> resultMap=groupServiceFacade.group(mrInfoMap,groupAddr,drgVersionDesc,groupAgain);
		Map<String,String> saveResult=groupServiceFacade.groupResultLogSave(mrInfoMap,resultMap,drgGroupVer,drgVersionDesc,verRegion,isICDMatch);
		if("false".equals(saveResult.get("error"))){
			String drgCode=saveResult.get("drgCode");
			if (drgCode.matches("^\\w{1,2}QY$")||drgCode.matches("^\\d{4}$")) {
				synchronized (processCaseCnt) {
					processCaseCnt[3]++;
				}
			} else {
				//记录分到的DRGs病组
				synchronized (drgsInGroupMap) {
					if(!drgsInGroupMap.contains(drgCode)){
						drgsInGroupMap.add(drgCode);
					}
				}
			}
		}else{
			//分组报错
			synchronized (processCaseCnt) {
				processCaseCnt[4]++;
			}
		}
		
	}
	
	/**
	 * 北京2016版分组器分组
	 * @param mrInfoGroupMap
	 */
	private void bj2016groupService(Map<String, Object> mrInfoMap){
		//分组器调用					
		Map<String,Object> resultMap=groupServiceFacade.group(mrInfoMap,groupAddr,drgVersionDesc,groupAgain);
		Map<String,String> saveResult=groupServiceFacade.groupResultLogSave(mrInfoMap,resultMap,drgGroupVer,drgVersionDesc,verRegion,isICDMatch);
		if("false".equals(saveResult.get("error"))){
			String drgCode=saveResult.get("drgCode");
			if (drgCode.matches("^\\w{1,2}QY$")||drgCode.matches("^\\d{4}$")) {
				synchronized (processCaseCnt) {
					processCaseCnt[3]++;
				}
			} else {
				//记录分到的DRGs病组
				synchronized (drgsInGroupMap) {
					if(!drgsInGroupMap.contains(drgCode)){
						drgsInGroupMap.add(drgCode);
					}
				}
			}
		}else{
			//分组报错
			synchronized (processCaseCnt) {
				processCaseCnt[4]++;
			}
		}
		
	}
    /**
	 * 
	 * @methodname    : loadProgress
	 * @description   : 首页数据分组加载进度
	 * @param         : 
	 * @author        : liqingyang
	 * @return        :
	 * @date          : 2017年3月17日
	 */
	public InvokeResult loadProgress(){
		Map<String, Object> drgGroupInfoMap = new HashMap<>();
		drgGroupInfoMap.put("mrGt60CountCurr", processCaseCnt[2]);//当前获取到的大于60天病例数
		drgGroupInfoMap.put("mrAssembleCountCurr", processCaseCnt[0]);//当前多线程组装病例数
		drgGroupInfoMap.put("mrGroupCount", processCaseCnt[1]);//当前分组病例数
		drgGroupInfoMap.put("notInCaseCnt", processCaseCnt[3]);//未入组病例数
		drgGroupInfoMap.put("drgVersionDesc", drgVersionDesc);//分组器版本
		drgGroupInfoMap.put("drgCountCurr", drgsInGroupMap.size());//获取当前已经分到的DRGs组数
		drgGroupInfoMap.put("groupErrorCaseCnt", processCaseCnt[4]);//分组报错的病例数
		return InvokeResult.success(drgGroupInfoMap);	
	}
	@Override
	public InvokeResult updateNotInReason(String dateFrom, String dateTo) {
		dateFrom = DrgsIndex.formateDateFrom(dateFrom) ;
		dateTo = DrgsIndex.formateDateTo(dateTo) ;
		notInAll = 1;
		notInUpdate = 0;
		//查询未入组的病例
		List<Object[]> groupingLogs = drgServiceGroupApplication.getNoInGroupingLog(dateFrom,dateTo);
		//更新每个病例的未入组原因
		int l = groupingLogs.size();
		notInAll = l;
		System.out.println("更新开始~~");
		for(int i= 0;i<l;i++){
			notInUpdate = i+1;
			judgeNotInReason(groupingLogs.get(i));
		}
		System.out.println("更新结束~~");
		return InvokeResult.success();
	}
	/**
	 * 
	 *  judgeNotInReason.  
	 *  @Description：判断未入组原因
	 *  @Author WENYI
	 *  @param gl 
	 *  @Date:2018年11月12日上午9:18:23
	 */
	private void judgeNotInReason(Object[] gl){
		ObjectMapper objectMapper = new ObjectMapper();
		String pMainIndex=gl[0]==null?"":gl[0].toString();
		String verDesc=gl[1]==null?"":gl[1].toString();//分组器版本描述
		String notInCode=gl[2]==null?"":gl[2].toString();
		Map<String, Object> mrInfo=new HashMap<>();
		mrInfo.put("ACCTUAL_DAYS", gl[3]==null?null:gl[3].toString());
		mrInfo.put("TOTAL_EXPENSE", gl[4]==null?null:gl[4].toString());
		mrInfo.put("DISEASE_CODE", gl[5]==null?null:gl[5].toString());
		Map<String, Object> resultMap=new HashMap<>();
		if(verDesc!=null&&verDesc.indexOf("北京2016版")>=0){
			List<Object[]> resultList=drgServiceGroupApplication.getOtherGroupResult(pMainIndex);
			if(resultList.size()>0){
				resultMap.put("error", resultList.get(0)[0]==null?null:resultList.get(0)[0].toString());
				resultMap.put("error_log", resultList.get(0)[1]==null?null:resultList.get(0)[1].toString());
				resultMap.put("mdcs_main", resultList.get(0)[2]==null?null:resultList.get(0)[2].toString());
			}
		}
		resultMap.put("drg", notInCode);
		
		List<String> logStr=new ArrayList<>();
		for(int i=6;i<gl.length;i++){
			if(gl[i]!=null){
				logStr.add(gl[i].toString());
			}
		}
		resultMap.put("log", logStr);
		
		try {
			String notInReasonJson=NotInGroupReasonUtil.notInGroupReason(objectMapper.writeValueAsString(mrInfo),objectMapper.writeValueAsString(resultMap),verDesc);
			String notInReason=DrgsIndex.notInReasonPharse(pMainIndex,notInReasonJson);
			//保存未入组原因
			drgServiceGroupApplication.saveNotInReason(pMainIndex, notInReason);
		}catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	@Override
	public InvokeResult getUpdateReasonProcess() {
		double percent = Arith.div(notInUpdate, notInAll , 4)*100;
		if(notInUpdate == notInAll)
		{
			percent=100;
		}
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("percent", percent);
		System.err.println(percent);
		return InvokeResult.success(map);
	}
	
	/**
	 * 根据对应的drgGroupVer值查询出对应的DRGVersion值
	 * @param drgGroupVer
	 * @return
	 */
	public DRGVersion getICDVersion(String drgGroupVer){
		DRGVersion drgVersion=null;
		if(drgGroupVer==null||"".equals(drgGroupVer.trim())){
			return drgVersion;
		}else{
			drgVersion=drgVersionApplication.getDRGVersion(drgGroupVer);
			return drgVersion;
		}
	}	
}
